﻿using System;
using System.Collections.Generic;
using Castle.MicroKernel;
using Castle.MicroKernel.SubSystems.Conversion;
using CMode = Castle.Core.ComponentModel;

namespace Mbs.CastleContainer
{
    /// <summary>
    /// 懒惰初始化装备
    /// </summary>
    public class LazyInitFacility:MbsFacility
    {
        private List<IHandler> waitList = new List<IHandler>();
        private ITypeConverter converter;

        public LazyInitFacility() : base(KernelListnerType.ComponentRegistered) { }


        // Don't check the waiting list while this flag is set as this could result in
        // duplicate singletons.
        private bool inStart;

        protected override void Init()
        {
            base.Init();
            converter = (ITypeConverter)Kernel.GetSubSystem(SubSystemConstants.ConversionManagerKey);
        }

        public override void OnComponentRegistered(string key, IHandler handler)
        {

            if (!HasLazyInit(handler.ComponentModel))
            {
                if (handler.CurrentState == HandlerState.WaitingDependency)
                    AddHandlerToWaitingList(handler);
                else
                    Start(key);
            }

            CheckWaitingList();
        }

        private void OnHandlerStateChanged(object source, EventArgs args)
        {
            CheckWaitingList();
        }

        private void AddHandlerToWaitingList(IHandler handler)
        {
            waitList.Add(handler);

            handler.OnHandlerStateChanged += new HandlerStateDelegate(OnHandlerStateChanged);
        }

        /// <summary>
        /// For each new component registered,
        /// some components in the WaitingDependency
        /// state may have became valid, so we check them
        /// </summary>
        private void CheckWaitingList()
        {
            if (!inStart)
            {
                IHandler[] handlers = waitList.ToArray();

                var validList = new List<IHandler>();

                foreach (IHandler handler in handlers)
                {
                    if (handler.CurrentState == HandlerState.Valid)
                    {
                        validList.Add(handler);
                        waitList.Remove(handler);

                        handler.OnHandlerStateChanged -= new HandlerStateDelegate(OnHandlerStateChanged);
                    }
                }

                foreach (IHandler handler in validList)
                    Start(handler.ComponentModel.Name);
            }
        }

        /// <summary>
        /// Request the component instance
        /// </summary>
        /// <param name="key"></param>
        private void Start(String key)
        {
            try
            {
                inStart = true;
                object instance = Kernel[key];
            }
            finally
            {
                inStart = false;
            }
        }

       
        private bool HasLazyInit(CMode model)
        {
            bool result = true;

            if (model.Configuration != null)
            {
                String startable = model.Configuration.Attributes["lazy-init"];

                if (startable != null)
                    result = (bool)converter.PerformConversion(startable, typeof(bool));
            }

            return result;
        }
    }
}
